<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 了解constructor的用法
        // 创建一个简单的的构造函数 User
        // function User() { }

        // // 创建一个User对象
        // var me = new User();

        // // 还是创建一个新的User对象（用前一个对象的const引用来创建）
        // var you = new me.constructor();

        // // 发现这两个对象的constructor实质上是一样的
        // console.log(me.constructor == you.constructor); //true

        // 对象的prototype对象添加的例子
        // function User(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // // 将一个新的函数添加到此对象的prototype对象中
        // User.prototype.getName = function () {
        //     return this.name;
        // }
        // // 并再给此prototype对象添加一个函数
        // // 注意其上下文是实例化后的对象
        // User.prototype.getAge = function () {
        //     return this.age;
        // }
        // // 实例化一个新的user对象
        // var user = new User('Bob', 22);
        // // 可以看到我们添加的这两个属性都在刚才创建的对象中，并且有合适的上下文
        // console.log(user.getName() == 'Bob');// true
        // console.log(user.getAge() == 22); //true


        // 私有方法
        // 表示教室的一个对象构造函数
        // function Classroom(students, teacher) {
        //     // 用于显示所有班上学生的私有方法
        //     function disp() {
        //         console.log(this.name);
        //     }
        //     // 将班级数据存入公共对象属性中
        //     this.students = students;
        //     this.teacher = teacher;
        //     // 调用私有方法来显示错误
        //     disp();
        // }
        // // 创建一个新的classRoom对象
        // var classRoom = new Classroom(['John', 'Bob'], 'Mr.Smith');
        // // 调用disp方法会失败，因为它不是该对象的公共属性
        // classRoom.disp();



        // 使用特权方法的例子
        // function User(name, age) {
        //     // 尝试计算用户出生的年份
        //     var year = (new Date()).getFullYear() - age;
        //     // 创建一个新的特权方法，能够访问year变量，同时自身属于公共可以访问的
        //     this.getYearBorn = function () {
        //         return year;
        //     }
        // }
        // // 创建一个实例化对象
        // var user = new User('Bob', 33);
        // // 验证返回的年份正确
        // console.log(user.getYearBorn());
        // // 注意我们无法访问该对象私有属性的年份属性
        // console.log(user.year == null); //true


        // 动态生成方法
        function User(properties) {
            // 遍历该对象的所有属性，并保证其作用域正确
            for (var i in properties) {
                (function (which) {
                    var p = i;
                    // 创建此属性的一个新的读取器（getter）
                    which['get' + p] = function () {
                        return properties[p];
                    }
                    // 创建此属性的一个设置器(setter)
                    which['set' + p] = function (val) {
                        properties[p] = val;
                    }
                })(this);
            }
        }
        // 创建一个新的实例，并且把两个属性的一个对象传入作为种子
        var user = new User({
            name: 'Bob',
            age: 33
        });
        // 注意name属性并不存在
        // 因为它是属性对象(properties object)的私有变量
        console.log(user.name == null); //true
        // 不过我们可以使用新生成的getName()方法来获取这个值
        // 因此函数是动态生成的
        console.log(user.getname() == 'Bob');//true
        user.setage(22);
        console.log(user.getage() == 22); //true


        // 静态方法
        User.cloneUser = function (user) {
            // 创建并返回一个新的用户
            return new User(
                // 这里是其它对象的复制
                user.getname(),
                user.getage()
            );
        };
    </script>
</body>

</html>